#include "DS1302.h"
/***********************************************************************
  * @代码说明：本代码内容用于快速使用DS1302
  * @作者：Astilbe
  * @日期：2020/07/26
  * @开发指导：wiki.stduino.com
  ***********************************************************************/
/* Includes ------------------------------------------------------------------*/
//例如：#include "stm32f10x_abc.h"
/*上面不用动，开始你的表演 ------------------------------------------------------------------*/
#include "DS1302.h"

TIME DS1302Data;
bool Flag_Time_Refresh = 1;

//****************************************************
//写入一字节：上升沿写入数据
//****************************************************
void DS1302_InputByte(unsigned char dat)    
{ 
    unsigned char i;

    pinMode(DS1302_IO,OUTPUT);

    for(i=0; i<8; i++)
    {
        if((dat & 0x01) == 1)
        {
            DS1302_IO_1;
        }
        else
        {
            DS1302_IO_0;
        }
          
        
        DS1302_CLK_0;               //低电平
        
        delayMicroseconds(2);
        
        DS1302_CLK_1;              //高电平，结合低电平，一次上升沿，写入数据
        
        delayMicroseconds(2);
        dat >>= 1; 
    } 
}

//****************************************************
//读取一字节：下降沿读取数据
//****************************************************
unsigned char DS1302_OutputByte(void)   
{ 
    unsigned char i;
    unsigned char dat;
    pinMode(DS1302_IO,INPUT);
    for(i=0; i<8; i++)
    {
        DS1302_CLK_1;                   //高电平
        delayMicroseconds(2);
        DS1302_CLK_0;                   //低电平，结合高电平，一次下降沿读出数据
        delayMicroseconds(2);
        dat >>= 1;                  
        if( digitalRead(DS1302_IO) == HIGH )
            dat |= 0x80;                //或运算，最高位置1
        else
            dat &= 0x7F;                //与运算，最高位清0      
    } 
    return(dat); 
}

//****************************************************
//写操作函数 Addr: DS1302地址, Data: 要写的数据
//读写操作，都需要RST置高电平，在这之前，CLK需要为低电平
//****************************************************
void DS1302_Write(unsigned char Addr, unsigned char Data) 
{
    DS1302_RST_0;                
    delayMicroseconds(2);
    DS1302_CLK_0;                       //CLK置为低电平
    delayMicroseconds(2);
    DS1302_RST_1;                       //RST置1
    delayMicroseconds(2);
    DS1302_InputByte(Addr);             // 访问地址
    DS1302_InputByte(Data);             // 写1字节数据
    DS1302_CLK_1;                       // 将时钟电平置于高电平状态 ，处于已知状态
    delayMicroseconds(2);
    DS1302_RST_0;                       //RST置0，终止传输
    delayMicroseconds(2);
}

//****************************************************
//读操作函数：包括读取数据的地址，时序同上
//****************************************************
unsigned char DS1302_Read(unsigned char Addr) 
{
    unsigned char Data;
    DS1302_RST_0;
    delayMicroseconds(2);
    DS1302_CLK_0;
    delayMicroseconds(2);
    DS1302_RST_1;
    delayMicroseconds(2);
    DS1302_InputByte(Addr|0x01);        // 地址，命令 
    Data = DS1302_OutputByte();         // 读1Byte数据
    DS1302_CLK_1;
    delayMicroseconds(2);
    DS1302_RST_0;
    delayMicroseconds(2);
    return(Data);
}

//****************************************************
//写保护：
//****************************************************
void DS1302_SetProtect(unsigned char flag)       
{
    if(flag)
        DS1302_Write(0x8E,0x80);            //保护
    else
        DS1302_Write(0x8E,0x00);            //不保护
} 

//****************************************************
// 设置时间函数
//****************************************************
void DS1302_SetTime(unsigned char Address, unsigned char Value)        
{
    DS1302_SetProtect(0);
    DS1302_Write(Address, ((Value/10)<<4 | (Value%10))); 
}

//****************************************************
//获取当前时间
//****************************************************
void DS1302_GetTime(TIME *Time)
{
    unsigned char ReadValue;
    ReadValue = DS1302_Read(DS1302_SEC);
    ReadValue = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);            //BCD码转换十进制
    if(ReadValue != DS1302Data.Second)                                //跟上一次状态不同，置位刷新标志位
        Flag_Time_Refresh = 1;
    Time->Second = ReadValue;

    ReadValue = DS1302_Read(DS1302_MIN);
    Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_Read(DS1302_HR);
    Time->Hour = ((ReadValue&0x20)>>4)*10 + (ReadValue&0x0F);
    if((ReadValue & 0xA0)==0xA0)//如果成立，为12进制，且为下午
    {
        Time->Hour -= 12;
    }
    
    
    ReadValue = DS1302_Read(DS1302_DAY);
    Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);    
    ReadValue = DS1302_Read(DS1302_WEEK);
    Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_Read(DS1302_MON);
    Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    ReadValue = DS1302_Read(DS1302_YEAR);
    Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);   
}

//****************************************************
//初始化：检查HALT标志
//****************************************************
void DS1302_Init(void)
{
    unsigned char Second;

    pinMode(DS1302_RST,OUTPUT);
    pinMode(DS1302_IO,OUTPUT);
    pinMode(DS1302_CLK,OUTPUT);

    Second = DS1302_Read(DS1302_SEC);
    if(Second&0x80)       
        DS1302_SetTime(DS1302_SEC,Second & 0x7f);    //开启振荡    
}
//****************************************************
//DS1302振荡器停止
//****************************************************
void DS1302_HALT(bool FLAG_ON)
{
    unsigned char Second;
    Second = DS1302_Read(DS1302_SEC);
    if(FLAG_ON == 0)
        DS1302_Write(DS1302_SEC,Second | 0x80);              //停止振荡
    else
        DS1302_Write(DS1302_SEC,Second & 0x7f);              //开启振荡
}

//****************************************************
//时间设置函数
//****************************************************
void Set_Time(String command)
{
  DS1302_HALT(0);     //停止振荡
  DS1302Data.Year   = command.substring(4,6).toInt();
  DS1302Data.Month  = command.substring(7,9).toInt();
  DS1302Data.Day    = command.substring(10,12).toInt();
  DS1302Data.Week   = command.substring(13,14).toInt();
  DS1302Data.Hour   = command.substring(15,17).toInt();
  DS1302Data.Minute = command.substring(18).toInt();   //从18位取到最后一位
  DS1302_SetTime( DS1302_YEAR , DS1302Data.Year );
  DS1302_SetTime( DS1302_MON , DS1302Data.Month );
  DS1302_SetTime( DS1302_DAY , DS1302Data.Day );
  DS1302_SetTime( DS1302_WEEK , DS1302Data.Week );
  DS1302_SetTime( DS1302_HR , DS1302Data.Hour );
  DS1302_SetTime( DS1302_MIN , DS1302Data.Minute );
  DS1302_HALT(1);    //启动振荡

  Show_RTCC();
}
//****************************************************
//时制设置：时寄存器（时钟寄存器左三，HR）
//第七位（bit 7）用来选择12小时制还是24小时制的时间显示模式。
//当为逻辑1时，为12小时制；当为逻辑0时，为24小时制。
//目前每次设置完毕 需要重启才能起效 还不知道怎么解决
//****************************************************
void Set_HourSystem(String hourSystem)
{

    unsigned char HR;
    HR = DS1302_Read(DS1302_HR);
    
    if(hourSystem == "set 24hours")
    {
      //DS1302_HALT(0);     //停止振荡
      DS1302_Write(DS1302_HR,HR & 0x7F); //置0
      Serial.println("目前为24小时制，当前时间为：");
      //DS1302_HALT(1);     
      Show_RTCC();
        
    }
    else if(hourSystem == "set 12hours")
    {
      //DS1302_HALT(0);     //停止振荡
      DS1302_Write(DS1302_HR,HR | 0x80);  //置1 
      Serial.println("目前为12小时制，当前时间为：");
      //DS1302_HALT(1);     //停止振荡
      Show_RTCC();
    }
    else
    {
       Serial.println("请输入\"24hour\"或\"12hours\"");
    }
}

//****************************************************
//显示当前时间
//****************************************************
void Show_RTCC()
{

  if(DS1302Data.Year < 10)
  {
    Serial.print("200");
  }
  else
  {
    Serial.print("20");
  }
  Serial.print(DS1302Data.Year);
  Serial.print('-');
  Serial.print(DS1302Data.Month);
  Serial.print('-');
  Serial.print(DS1302Data.Day);

  Serial.print("   ");

  switch(DS1302Data.Week)
  {
    case 1:
        Serial.println("Mon");         //显示星期一
        break;
    case 2:
        Serial.println("Tue");         //显示星期二
        break;
    case 3:
        Serial.println("Wed");         //显示星期三
        break;
    case 4:
        Serial.println("Thu");         //显示星期四
        break;
    case 5:
        Serial.println("Fri");         //显示星期五
        break;
    case 6:
        Serial.println("Sat");         //显示星期六
        break;
    case 7:
        Serial.println("Sun");         //显示星期日
        break;
    default : break;            
  }

  Serial.print(DS1302Data.Hour);
  Serial.print(':');
  Serial.print(DS1302Data.Minute);
  Serial.print(':');
  Serial.println(DS1302Data.Second);
}